<?php

namespace Xin\Setting;

use Xin\Capsule\WithConfig;
use Xin\Setting\Contracts\Repository as RepositoryContract;
use Xin\Setting\Exceptions\NotFountSettingItemException;
use Xin\Support\Arr;

abstract class AbstractRepository implements RepositoryContract
{
	use WithConfig;

	/**
	 * @var array
	 */
	protected $config;

	/**
	 * 初始化构造器
	 * @param array $config
	 */
	public function __construct(array $config)
	{
		$this->config = $config;
	}

	/**
	 * 是否存在配置
	 * @param string $key
	 * @return bool
	 * @throws NotFountSettingItemException
	 */
	public function hasInfo($key)
	{
		return !!$this->info($key);
	}

	/**
	 * @inerhitDoc
	 * @throws NotFountSettingItemException
	 */
	public function info($key, $fail = false)
	{
		$result = $this->infos([$key]);

		if (!$fail) {
			return isset($result[$key]) ? $result[$key] : null;
		}

		if (!isset($result[$key])) {
			throw new NotFountSettingItemException($key);
		}

		return $result[$key];
	}

	/**
	 * @inerhitDoc
	 */
	public function upsert($key, $info, bool $serialize = false)
	{
		$result = $this->multipleUpsert([
			$key => $info,
		], $serialize);

		return isset($result[$key]) ? $result[$key] : null;
	}

	/**
	 * @inerhitDoc
	 */
	public function multipleUpsert(array $items, bool $detaching = false, bool $serialize = false)
	{
		$targetKeys = array_keys($items);
		$existKeys = $this->getExistsKeys($targetKeys);

		//		$attachKeys = array_diff($targetKeys, $existKeys);
		$detachKeys = array_diff($existKeys, $targetKeys);
		//		$updateKeys = array_diff($existKeys, $detachKeys);

		// 移除元素
		if ($detaching && count($detachKeys) > 0) {
			$this->deletes($detachKeys);
		}

		// 存放的结果数据
		$result = [];
		foreach ($targetKeys as $targetKey) {
			$setting = $items[$targetKey];
			$setting = Arr::only($setting, ['title', 'alias', 'type', 'value', 'extra', 'group', 'display']);

			// 添加元素
			if (!in_array($targetKey, $existKeys)) {
				$result[$targetKey] = $this->create(
					array_merge([
						'title' => '',
						'alias' => '',
						'type' => 'string',
						'value' => '',
						'extra' => '',
						'group' => '',
						'display' => 1,
						'system' => 0,
						'sort' => 0,
					], $setting, [
						'name' => $targetKey,
					]),
					$serialize
				);
			} else { // 更新元素
				$result[$targetKey] = $this->update($targetKey, $setting, $serialize);
			}
		}

		return $result;
	}

	/**
	 * 获取已存在的key
	 * @return array
	 */
	abstract protected function getExistsKeys(array $keys);

	/**
	 * 创建配置
	 * @param array $data
	 * @param bool $serialize
	 * @return array
	 */
	abstract protected function create(array $data, bool $serialize = false);

	/**
	 * 更新配置
	 * @param string $key
	 * @param array $data
	 * @param bool $serialize
	 * @return array
	 */
	abstract protected function update($key, array $data, bool $serialize = false);

	/**
	 * @inerhitDoc
	 */
	public function delete($key)
	{
		return $this->deletes([$key]);
	}


	/**
	 * @inerhitDoc
	 */
	public function get($key, $default = null)
	{
		return $this->getMultiple([$key], $default)[$key];
	}


	/**
	 * @inerhitDoc
	 */
	public function set($key, $value)
	{
		$this->setMultiple([
			$key => $value,
		]);
	}
}
